package com.gydz.pcjjq.model.service;

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.support.annotation.Nullable;

import com.blankj.utilcode.util.ConvertUtils;
import com.blankj.utilcode.util.LogUtils;
import com.google.common.primitives.Bytes;
import com.gydz.pcjjq.app.Constants;
import com.gydz.pcjjq.event.CmdR4403Event;
import com.gydz.pcjjq.model.bean.Cmd4403Bean;
import com.gydz.pcjjq.event.CmdT4481Event;
import com.gydz.pcjjq.event.CmdT4482Event;
import com.gydz.pcjjq.event.CmdT8001Event;
import com.gydz.pcjjq.model.bean.PassengerInfoBean;
import com.gydz.pcjjq.utils.ConvertUtilsPlus;

import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;

import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class SerialControlService extends Service {

    private String mDevicePath = "/dev/ttyMT1";

    private int mBaudrate = 115200;

    private FileDescriptor mFileDescriptor;
    private FileInputStream mInputStream;
    private FileOutputStream mOutputStream;
    private ReceiveThread mReceiveThread;
    private ExecutorService mSingleThreadExecutor;
    private boolean mIsInitSuccess;
    private byte[] mKey2;
    private byte[] mA2;
    private byte[] mB2;
    private byte[] mC2;
    private byte[] mKey1;
    private byte[] mA1;
    private byte[] mB1;
    private byte[] mC1;

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return new Binder();
    }

    @Override
    public void onCreate() {
        super.onCreate();
        EventBus.getDefault().register(this);
        mIsInitSuccess = initSerialPort();
        if (!mIsInitSuccess) {
            return;
        }
        mReceiveThread = new ReceiveThread();
        mSingleThreadExecutor = Executors.newSingleThreadExecutor();

        if (mIsInitSuccess) {
            mReceiveThread.start();
            LogUtils.w("串口控制服务已开启");
        } else {
            stopSelf();
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        EventBus.getDefault().unregister(this);
        if (!mIsInitSuccess) {
            return;
        }
        mReceiveThread.interrupt();
        close();
    }

    private boolean initSerialPort() {
        mFileDescriptor = open(mDevicePath, mBaudrate, 0);
        if (mFileDescriptor != null) {
            LogUtils.w("串口打开成功");
            mInputStream = new FileInputStream(mFileDescriptor);
            mOutputStream = new FileOutputStream(mFileDescriptor);
        } else {
            LogUtils.e("串口打开失败");
            return false;
        }
        return true;
    }

    private class ReceiveThread extends Thread {

        private int mRecLen = 0;
        private final int mMinMsgLen = 14;

        private ArrayList<Byte> mBufferList = new ArrayList<>();

        @Override
        public void run() {
            super.run();
            int size;
            while (!isInterrupted()) {
                try {
                    byte[] buffer = new byte[1024];
                    if (mInputStream == null) {
                        return;
                    }
                    size = mInputStream.read(buffer);
                    if (size > 0) {
                        for (int i = 0; i < size; i++) {
                            mBufferList.add(buffer[i]);
                        }
//                        LogUtils.w("收到命令：" + new String(Bytes.toArray(mBufferList)) + "____" + ConvertUtils.bytes2HexString(Bytes.toArray(mBufferList)));
                        mRecLen += size;
                        parseSerialCmd();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                    return;
                }
            }
        }

        private void parseSerialCmd() {
            while (mRecLen >= mMinMsgLen) {
                if ((Bytes.toArray(mBufferList)[0] == (byte) 0x2A) && (Bytes.toArray(mBufferList)[1] == (byte) 0x47)
                        && (Bytes.toArray(mBufferList)[2] == (byte) 0x59)  && (Bytes.toArray(mBufferList)[3] == (byte) 0x3A)) {
                    int pkgDataLen = ConvertUtilsPlus.byte2UnsignedShort(Bytes.toArray(mBufferList)[13]);
                    pkgDataLen <<= 8;
                    pkgDataLen = pkgDataLen & 0x00000700;
                    pkgDataLen += ConvertUtilsPlus.byte2UnsignedShort(Bytes.toArray(mBufferList)[12]);
                    int pkgLen = 14 + pkgDataLen;
                    if (mRecLen >= pkgLen) {
                        byte[] pkg = new byte[pkgLen];
                        System.arraycopy(Bytes.toArray(mBufferList), 0, pkg, 0, pkgLen);
                        byte[] pkgBody = new byte[pkgLen - 14];
                        System.arraycopy(pkg, 14, pkgBody, 0, pkgLen - 14);
                        byte[] crc = new byte[]{pkg[5], pkg[4]};
                        byte[] cmd = new byte[]{pkg[7], pkg[6]};
                        byte[] serialNumber = new byte[]{pkg[11], pkg[10], pkg[9], pkg[8]};
                        int encryptionMode = ConvertUtilsPlus.byte2UnsignedShort(Bytes.toArray(mBufferList)[13]) >> 3 & 0x3;
                        int subcontractMode = ConvertUtilsPlus.byte2UnsignedShort(Bytes.toArray(mBufferList)[13]) >> 4 & 0x1;
                        int checkMode = ConvertUtilsPlus.byte2UnsignedShort(Bytes.toArray(mBufferList)[13]) >> 5 & 0x3;


                        String data = "整包数据（Hex）：" + ConvertUtils.bytes2HexString(pkg)
//                                + "\n整包数据（ASCII）：" + new String(pkg)
//                                + "\n数据段数据（Hex）：" + ConvertUtils.bytes2HexString(pkgBody)
                                + "\n检验：0x" + ConvertUtils.bytes2HexString(crc) + " 命令字：0x" + ConvertUtils.bytes2HexString(cmd)
                                + " 流水号：0x" + ConvertUtils.bytes2HexString(serialNumber) + " 数据长度：0x" + Integer.toHexString(pkgDataLen)
                                + "(" + pkgDataLen + ") 加密方式：0x" + Integer.toHexString(encryptionMode)
                                + " 分包标识：0x" + Integer.toHexString(subcontractMode) + " 校验方式：0x" + Integer.toHexString(checkMode);

//                        LogUtils.w(data);
                        switch (ConvertUtils.bytes2HexString(cmd)) {
                            case "4403":
//                                EventBus.getDefault().post(new CmdT8001Event(ConvertUtils.bytes2HexString(cmd), 0));
                                if (mKey2 != null && mA2 != null && mB2 != null && mC2 != null) {
                                    ConvertUtilsPlus.encrypt(Long.parseLong(ConvertUtils.bytes2HexString(mKey1), 16),
                                            Long.parseLong(ConvertUtils.bytes2HexString(mA1), 16),
                                            Long.parseLong(ConvertUtils.bytes2HexString(mB1), 16),
                                            Long.parseLong(ConvertUtils.bytes2HexString(mC1), 16),
                                            pkgBody, pkgBody.length);

                                    Cmd4403Bean cmd4403Bean = new Cmd4403Bean();
                                    cmd4403Bean.setCurrentTime(Long.parseLong(ConvertUtils.bytes2HexString(new byte[] {pkgBody[3], pkgBody[2], pkgBody[1], pkgBody[0]}), 16));
                                    cmd4403Bean.setPrice(Integer.parseInt(ConvertUtils.bytes2HexString(new byte[] {pkgBody[5], pkgBody[4]}), 16));
                                    cmd4403Bean.setDiscount(Integer.parseInt(ConvertUtils.bytes2HexString(new byte[] {pkgBody[6]}), 16));
                                    cmd4403Bean.setCarSeatState(pkgBody[7] & 0x1);
                                    cmd4403Bean.setCarSpeed((pkgBody[7] >> 1) & 0x1);
                                    cmd4403Bean.setCarDrivingState((pkgBody[7] >> 2) & 0x1);
                                    for (int i = 0; i < 4; i++) {
                                        int j = i * 16;
                                        cmd4403Bean.getPassengerInfos().get(i).setPassengerNumber(i + 1);
                                        cmd4403Bean.getPassengerInfos().get(i).setMileage(Long.parseLong(ConvertUtils.bytes2HexString(new byte[] {pkgBody[11 + j], pkgBody[10 + j], pkgBody[9 + j], pkgBody[8 + j]}), 16));
                                        cmd4403Bean.getPassengerInfos().get(i).setWaitTime(Long.parseLong(ConvertUtils.bytes2HexString(new byte[] {pkgBody[15 + j], pkgBody[14 + j], pkgBody[13 + j], pkgBody[12 + j]}), 16));
                                        cmd4403Bean.getPassengerInfos().get(i).setShouldPay(Long.parseLong(ConvertUtils.bytes2HexString(new byte[] {pkgBody[19 + j], pkgBody[18 + j], pkgBody[17 + j], pkgBody[16 + j]}), 16));
                                        cmd4403Bean.getPassengerInfos().get(i).setRealPay(Long.parseLong(ConvertUtils.bytes2HexString(new byte[] {pkgBody[23 + j], pkgBody[22 + j], pkgBody[21 + j], pkgBody[20 + j]}), 16));
                                        if (cmd4403Bean.getPassengerInfos().get(i).getShouldPay() == 0 && cmd4403Bean.getPassengerInfos().get(i).getRealPay() == 0) {
                                            cmd4403Bean.getPassengerInfos().get(i).setSeatStatus(Constants.ITEM_PASSENGER_INFO_2);
                                        } else {
                                            cmd4403Bean.getPassengerInfos().get(i).setSeatStatus(Constants.ITEM_PASSENGER_INFO_1);
                                        }
                                    }
                                    LogUtils.w(cmd4403Bean.toString());
                                    EventBus.getDefault().post(new CmdR4403Event(cmd4403Bean));
                                } else {
                                    EventBus.getDefault().post(new CmdT4481Event());
                                }
                                break;
                            case "4401":
                                mKey1 = new byte[] {pkgBody[3], pkgBody[2], pkgBody[1], pkgBody[0]};
                                mA1 = new byte[] {pkgBody[7], pkgBody[6], pkgBody[5], pkgBody[4]};
                                mB1 = new byte[] {pkgBody[11], pkgBody[10], pkgBody[9], pkgBody[8]};
                                mC1 = new byte[] {pkgBody[15], pkgBody[14], pkgBody[13], pkgBody[12]};

                                byte[] keyBody = new byte[100];
                                System.arraycopy(pkgBody, 12, keyBody, 0, 100);
                                ConvertUtilsPlus.encrypt(Integer.parseInt(ConvertUtils.bytes2HexString(mKey1), 16),
                                        Integer.parseInt(ConvertUtils.bytes2HexString(mA1), 16),
                                        Integer.parseInt(ConvertUtils.bytes2HexString(mB1), 16),
                                        Integer.parseInt(ConvertUtils.bytes2HexString(mC1), 16),
                                        keyBody, keyBody.length);

                                byte[] licensePlateNumber = new byte[12];
                                System.arraycopy(keyBody, 88, licensePlateNumber, 0, 12);
                                ConvertUtilsPlus.reverseArray(licensePlateNumber);

                                mKey2 = new byte[] {keyBody[3], keyBody[2], keyBody[1], keyBody[0]};
                                mA2 = new byte[] {keyBody[7], keyBody[6], keyBody[5], keyBody[4]};
                                mB2 = new byte[] {keyBody[11], keyBody[10], keyBody[9], keyBody[8]};
                                mC2 = new byte[] {keyBody[15], keyBody[14], keyBody[13], keyBody[12]};

                                data += "\n" + ConvertUtils.bytes2HexString(mKey1) + " " + ConvertUtils.bytes2HexString(mA1) + " " + ConvertUtils.bytes2HexString(mB1) + " " + ConvertUtils.bytes2HexString(mC1)
                                + " " + new String(licensePlateNumber) + "\n" + ConvertUtils.bytes2HexString(mKey2) + " " + ConvertUtils.bytes2HexString(mA2) + " " + ConvertUtils.bytes2HexString(mB2) + " " + ConvertUtils.bytes2HexString(mC2);
                                LogUtils.e(data);
                                break;
                            case "0001":
                                byte[] cmd0001 = new byte[] {pkgBody[1], pkgBody[0]};
                                byte reply = pkgBody[2];
                                LogUtils.e(ConvertUtils.bytes2HexString(cmd0001) + " " + reply);
                                break;
                            default:
                                break;
                        }

                        mRecLen -= pkgLen;
                        for (int i = 0; i < pkgLen; i++) {
                            mBufferList.remove(0);
                        }
                    } else {
                        break;
                    }

                } else {
                    mRecLen -= 1;
                    mBufferList.remove(0);
                }
            }
        }
    }

    private class Send4481CmdThread extends Thread {

        private byte[] mCmd = ConvertUtils.hexString2Bytes("2A47593AD600814401000000100000000000000000000000000000000000");

        @Override
        public void run() {
            super.run();
            if (mCmd != null && mOutputStream != null) {
                try {
                    mOutputStream.write(mCmd);
                    LogUtils.e("已发送命令：" + ConvertUtils.bytes2HexString(mCmd));
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private class Send8001CmdThread extends Thread {

        private byte[] mCmd = ConvertUtils.hexString2Bytes("2A47593A EA01 0180 FA1D0701 0300 0344 00".replace(" ", ""));

        public Send8001CmdThread(CmdT8001Event cmdT8001Event) {
            byte[] bytes = ConvertUtils.hexString2Bytes(cmdT8001Event.getCmd());
            mCmd[14] = bytes[1];
            mCmd[15] = bytes[0];
            mCmd[16] = (byte) cmdT8001Event.getReply();

            int sum = 0;
            for (int i = 0; i < 11; i++) {
                sum += (mCmd[i + 6] & 0xff);
            }
            byte[] checks = ConvertUtils.hexString2Bytes(Long.toHexString(sum));
            mCmd[4] = checks[1];
            mCmd[5] = checks[0];

        }

        @Override
        public void run() {
            super.run();
            if (mCmd != null && mOutputStream != null) {
                try {
                    mOutputStream.write(mCmd);
                    LogUtils.e("已发送命令：" + ConvertUtils.bytes2HexString(mCmd));
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private class Send4482CmdThread extends Thread {

        private byte[] mCmd = ConvertUtils.hexString2Bytes("2A47593A F201 8244 FA1D0701 0500 02 03 02 01 00".replace(" ", ""));

        public Send4482CmdThread(CmdT4482Event cmdT4482Event) {
            mCmd[14] = (byte) cmdT4482Event.getTotalNumber();
            mCmd[15] = (byte) ((cmdT4482Event.getFourIsPause() << 7) + (cmdT4482Event.getThreeIsPause() << 6) +
                    (cmdT4482Event.getTwoIsPause() << 5) + (cmdT4482Event.getOneIsPause() << 4) +
                    (cmdT4482Event.getFourIsVacancy() << 3) + (cmdT4482Event.getThreeIsVacancy() << 2) +
                    (cmdT4482Event.getTwoIsVacancy() << 1) + cmdT4482Event.getOneIsVacancy());
            mCmd[16] = (byte) cmdT4482Event.getPassengerNumber();
            mCmd[17] = (byte) cmdT4482Event.getIsGettingOff();
            mCmd[18] = (byte) cmdT4482Event.getIsPrint();
            int sum = 0;
            for (int i = 0; i < 13; i++) {
                sum += (mCmd[i + 6] & 0xff);
            }
            byte[] checks = ConvertUtils.hexString2Bytes(Long.toHexString(sum));
            mCmd[4] = checks[1];
            mCmd[5] = checks[0];
        }

        @Override
        public void run() {
            super.run();
            if (mCmd != null && mOutputStream != null) {
                try {
                    mOutputStream.write(mCmd);
                    LogUtils.e("已发送命令：" + ConvertUtils.bytes2HexString(mCmd));
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onMessageEventSend4481Cmd(CmdT4481Event cmdT4481Event) {
        if (!mIsInitSuccess) {
            return;
        }
        mSingleThreadExecutor.execute(new Send4481CmdThread());
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onMessageEventSend4482Cmd(CmdT4482Event cmdT4482Event) {
        if (!mIsInitSuccess) {
            return;
        }
        mSingleThreadExecutor.execute(new Send4482CmdThread(cmdT4482Event));
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onMessageEventSend8001Cmd(CmdT8001Event cmdT8001Event) {
        if (!mIsInitSuccess) {
            return;
        }
        mSingleThreadExecutor.execute(new Send8001CmdThread(cmdT8001Event));
    }

    static {
        System.loadLibrary("SerialPort");
    }

    private native FileDescriptor open(String path, int baudrate, int flags);

    private native void close();
}